/************************************************************************
  Driver for the weight sensor MP40 and for the signal amplifier AD8555.                                                               
************************************************************************/

#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>
#include <avr/interrupt.h>
#include "weight_sensor.h"
#include "eeprom_.h"
#include "lcd162.h"

// AD8555 programing codes
#define SIMULATE_PARAMETER_VALUE 0b00000001
#define SECOND_STAGE_GAIN_CODE   0b00000000
#define FIRST_STAGE_GAIN_CODE    0b00000001
#define OUTPUT_OFFSET_CODE       0b00000010

// AD855 pins  and ports
#define VOUT 0
#define FILT 1
#define DIGI_IN 2
#define AMP_PORT PORTA
#define AMP_PIN PINA
#define AMP_DDR DDRA 




#define NUM_SAMPLES 4000

// Counts the samples for the mean calculation
uint16_t samples_counter = 0;

// Temp variable for the mean calculation
uint32_t measure = 0;
// Mean
uint16_t weight_mean = 0;

// EEPROM calibration data.
uint8_t calibration_code;
uint16_t calibration_ADC_0;

void WeightCalibrationUpdate();
void WeightFiltering();
int16_t WeightRead();
uint16_t WeightNoCalibrated();
void ADCInit();
void WeightSensorInit();

void setOutputOffset(uint8_t offset);
void setSecondStageGain(uint8_t gain);

// Returns the weight filtered but not calibrated
void WeightCalibrationUpdate()
{
	calibration_ADC_0 = EEPROMReadWord(ADDRESS_NO_LOAD);
}

void WeightFiltering()
{	
	// mean of NUM_SAMPLES samples.
	measure += ADCW;
	samples_counter++;
	if (samples_counter == NUM_SAMPLES)
	{	
		weight_mean = (measure/NUM_SAMPLES);	

		samples_counter = 0;
		measure = 0;
	}				
}

int16_t WeightRead()
{			
	int32_t temp = ((weight_mean - calibration_ADC_0) << 1); // 2*(ADC_read - ADC_0)
	return (int16_t)temp;
}

uint16_t WeightNoCalibrated()
{	
	return weight_mean;
}

void ADCInit()
{
	// External AREF reference, Input = ADC0 single ended
	ADMUX = 0b00000000;
	// ADC enable
	// ADC interrupt Enabled
	// ADC prescaler = 64 (=> ADC clock = 8 MHz / 64 = 125 kHZ)
	// Auto triggered conversions: 13.5 cycles -> 108 us per conversion
	// OBS : Bit ADATE = 1 => "Auto triggering" enabled.
	 ADCSRA = 0b11101110;
	// "Trigger Source" = "Free Running Mode"
	SFIOR = 0b00000000;
	// Start first conversion
	ADCSRA |= 1<<ADSC;
}

void WeightSensorInit()
{
	// Prepare pin DIGIN (output from Mega16, starting low) 
	AMP_PORT &= ~(1<<DIGI_IN); 
	AMP_DDR |= (1<<DIGI_IN);
	// Sensor amplifier : First stage gain
	// For debugging purposes, if code > 127 it means it has been erased.
	calibration_code = EEPROMReadByte(ADDRESS_CODE);
	if (calibration_code < 127)
	{
		setFirstStageGain(calibration_code);
	}
	else
	{
		// default gain	from lab test.
		setFirstStageGain(72);	
	}
	
	// Sensor amplifier : Second stage gain = 200
	setSecondStageGain(7);
	// Sensor amplifier : Offset = 0 volt
	setOutputOffset(0);
	
	ADCInit();
	// Sets  the ADC empty weight
	WeightCalibrationUpdate();
}

// For testing purposes only
void ShowWeight()
{
	while (1)
	{
		LCDClear();
		LCDDispInteger(WeightRead());
		LCDDispString("  ");
		LCDDispInteger(ADCW);
		LCDDispString("  ");
		LCDDispInteger(calibration_ADC_0);
		LCDGotoXY(0,1);
		LCDDispInteger(calibration_code);
		LCDDispString("  ");
		LCDDispInteger(0);
		LCDDispString("  ");
		LCDDispInteger(0);
		LCDDispString("  ");
		_delay_ms(100);
	}
}

// ADC conversion finished interruption
ISR(ADC_vect)
{
	WeightFiltering();
}


/*-----------------------------------------------------------------------
	Signal Amplifier AD8555.
	Obtained from Henning Hargaard driver.
----------------------------------------------------------------------*/
void sendData(uint8_t data);
void startOfPacket();
void endOfPacket();
void sendSensorCommand(uint8_t field_1, uint8_t field_2, uint8_t field_4);
void setFirstStageGain(uint8_t gain);
void setSecondStageGain(uint8_t gain);
void setOutputOffset(uint8_t offset);
	
void sendData(uint8_t data)
{
	// Disable interrupts
	cli();
	// Set pin DIGIN high
	AMP_PORT |= 1<<DIGI_IN; 
	if (data != 0)
	{
		// If data = 1: Minimum 50uS delay
		_delay_us(51);
	}else
	{
		// If data = 0: Pulse width must be between 50 ns and 10 us
		_delay_us(10);
	}		
	// Set pin DIGIN low
	AMP_PORT &= ~(1<<DIGI_IN);
	sei();
	// Minimum 10uS delay between pulses 
	_delay_us(11);
}

void startOfPacket()
{
	// Send Field 1 (12-Bit Start of Packet 1000 0000 0001)
	sendData(1);
	for (uint8_t i = 0; i < 10; i++)
		sendData(0);
	sendData(1);
}

void endOfPacket()
{
	// Send Field 5 (12-Bit End of Packet 0111 1111 1110)
	sendData(0);
	for (uint8_t i = 0; i < 10; i++)
		sendData(1);
	sendData(0);
}

void sendSensorCommand(uint8_t field_1, uint8_t field_2, uint8_t field_4)
{
	uint8_t i;
	uint8_t mask;
	uint8_t tmp;

  // Send Field 0 (Start of Packet)
  startOfPacket();
  
  // Send Field 1 (2 bit command)
  sendData(field_1 & 0b00000010); 
  sendData(field_1 & 0b00000001);
  
  // Send Field 2 (2 bit command)
  sendData(field_2 & 0b00000010); 
  sendData(field_2 & 0b00000001);
  
  // Send Field 3 (2-Bit Dummy 10)
  sendData(1);
  sendData(0);
  
  // Send Field 4 (8-Bit Value)
  mask = 0b10000000;
  tmp = field_4;
  for (i=0; i<8; i++)
  {
    sendData(tmp & mask);
    mask>>=1;
  }
  // simplify temp?

  // Send Field 5 (End of Packet)
  endOfPacket();
}

void setFirstStageGain(uint8_t gain)
{
  sendSensorCommand(SIMULATE_PARAMETER_VALUE, FIRST_STAGE_GAIN_CODE, (gain & 0x7F));
}

// 0 => 17,5; 7 => 200;
void setSecondStageGain(uint8_t gain)
{
  sendSensorCommand(SIMULATE_PARAMETER_VALUE, SECOND_STAGE_GAIN_CODE, (gain & 0x07));
}
 
// 0 => 0 volt; 255 => 5 volt;
void setOutputOffset(uint8_t offset)
{
  sendSensorCommand(SIMULATE_PARAMETER_VALUE, OUTPUT_OFFSET_CODE, offset);
}
